﻿using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.Extensions.Options;
using LaserMark.Components.Services;
using LaserMark.Control.Service;
using LaserMark.DataAccess.Models;
using LaserMark.DataAccess.Service;
using LaserMark.ModbusTCP;
using LaserMark.ModbusTCP.Abstraction;
using LaserMark.View.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using Timer = System.Threading.Timer;

namespace LaserMark.Components
{
    public partial class AxisStatus : IDisposable
    {
        [Inject]
        [NotNull]
        private IControl? Control { get; set; }

        [Inject]
        [NotNull]
        private IMasterClientFactory? MasterClientFactory { get; set; }

        [Inject]
        [NotNull]
        private IAuditService? AuditService { get; set; }

        [Inject]
        [NotNull]
        private IOptions<MarkOption>? Options { get; set; }

        [NotNull]
        private MarkOption? MarkOptions { get; set; }

        [NotNull]
        private Color Axis2Servo { get; set; } = Color.Secondary;

        [NotNull]
        private Color Axis2Limit { get; set; } = Color.Secondary;

        [NotNull]
        private Color Axis3Servo { get; set; } = Color.Secondary;

        [NotNull]
        private Color Axis3Limit { get; set; } = Color.Secondary;

        [NotNull]
        private Color Axis4Servo { get; set; } = Color.Secondary;

        [NotNull]
        private Color Axis4Limit { get; set; } = Color.Secondary;

        [NotNull]
        private Color Axis4Limit2 { get; set; } = Color.Secondary;

        [NotNull]
        private string? Enc1 { get; set; } = "0.00";

        [NotNull]
        private string? Enc2 { get; set; } = "0.00";

        [NotNull]
        private string? Enc3 { get; set; } = "0.00";

        private double XPluse { get; set; }

        private double YPluse { get; set; }

        private double ZPluse { get; set; }

        private string? Height { get; set; } = "0";

        private bool IsAxis2 { get; set; } = true;

        private bool IsAxis3 { get; set; } = true;

        private bool IsAxis4 { get; set; } = true;

        private bool IsAxis4Nav { get; set; } = true;

        private bool IsServo2 { get; set; } = true;

        private bool IsServo3 { get; set; } = true;

        private bool IsServo4 { get; set; } = true;

        private bool IsFirst { get; set; } = true;

        [NotNull]
        [Inject]
        private IGlobalStatus? GlobalStatus { get; set; }

        [NotNull]
        private ModBusMaster? Master { get; set; }

        private CancellationTokenSource? Token { get; set; } = new();

        protected override async Task OnInitializedAsync()
        {
            await base.OnInitializedAsync();
            MarkOptions = Options.Value;
            Master = MasterClientFactory.Create();
            await Master.ConnectAsync();

            System.Timers.Timer timer = new System.Timers.Timer(300);
            timer.Elapsed += Timer_Elapsed;
            timer.Start();

            System.Timers.Timer timer1 = new System.Timers.Timer(5000);
            timer1.Elapsed += Timer_Elapsed1;
            timer1.Start();

        }                                  

        private async void Timer_Elapsed(object? sender, ElapsedEventArgs e)
        {
            try
            {
                if (GlobalStatus.IsRunning)
                {
                    await Control.GetAxisStatus(0, (short)MarkOptions.AxisCode.X, out int value2, 1, out _);
                    await Control.GetAxisStatus(0, (short)MarkOptions.AxisCode.Y, out int value3, 1, out _);
                    await Control.GetAxisStatus(0, (short)MarkOptions.AxisCode.Z, out int value4, 1, out _);
                    mc.GT_GetEncPos(0, (short)MarkOptions.AxisCode.X, out double enc1, 1, out _);
                    Enc1 = (Convert.ToDouble(enc1) * MarkOptions.XPluse.Value).ToString("0.00");
                    mc.GT_GetEncPos(0, (short)MarkOptions.AxisCode.Y, out double enc2, 1, out _);
                    Enc2 = (Convert.ToDouble(enc2) * MarkOptions.YPluse.Value).ToString("0.00");
                    mc.GT_GetEncPos(0, (short)MarkOptions.AxisCode.Z, out double enc3, 1, out _);
                    Enc3 = (Convert.ToDouble(enc3) * MarkOptions.ZPluse.Value).ToString("0.00");

                    //使能
                    if ((value2 & 0x200) != 0)
                    {
                        Axis2Servo = Color.Danger;
                    }
                    else
                    {
                        Axis2Servo = Color.Success;
                    }

                    if ((value3 & 0x200) != 0)
                    {
                        Axis3Servo = Color.Danger;
                    }
                    else
                    {
                        Axis3Servo = Color.Success;
                    }

                    if ((value4 & 0x200) != 0)
                    {
                        Axis4Servo = Color.Danger;
                    }
                    else
                    {
                        Axis4Servo = Color.Success;
                    }

                    //2#正负限位
                    if ((value2 & 0x20) != 0)
                    {
                        Axis2Limit = Color.Danger;
                        if (IsAxis2 && !IsFirst)
                        {
                            IsAxis2 = false;
                            GlobalStatus.AuditLog.Add(new AuditLog() { Description = $"X轴限位触发", Result = Error.Error });
                            await Control.AxisOff(0, (short)MarkOptions.AxisCode.X);
                            mc.GT_SetDoBit(0, mc.MC_GPO, 1, 1);
                            mc.GT_SetDoBit(0, mc.MC_GPO, 2, 0);
                            GlobalStatus.IsEmergencyStop = true;
                            GlobalStatus.IsLimitX = true;
                        }
                    }
                    else
                    {
                        GlobalStatus.IsLimitX = false;
                        IsAxis2 = true;
                        Axis2Limit = Color.Success;
                    }

                    //3#正负限位
                    if ((value3 & 0x20) == 0)
                    {
                        Axis3Limit = Color.Success;
                        IsAxis3 = true;
                        GlobalStatus.IsLimitY = false;
                    }
                    else
                    {
                        Axis3Limit = Color.Danger;
                        if (IsAxis3 && !IsFirst)
                        {
                            IsAxis3 = false;
                            GlobalStatus.AuditLog.Add(new AuditLog() { Description = $"Y轴限位触发", Result = Error.Error });
                            await Control.AxisOff(0, (short)MarkOptions.AxisCode.Y);
                            mc.GT_SetDoBit(0, mc.MC_GPO, 1, 1);
                            mc.GT_SetDoBit(0, mc.MC_GPO, 2, 0);
                            GlobalStatus.IsEmergencyStop = true;
                            GlobalStatus.IsLimitY = true;
                        }
                    }

                    //4#正限位
                    if ((value4 & 0x20) == 0)
                    {
                        Axis4Limit = Color.Success;
                        IsAxis4 = true;
                        GlobalStatus.IsLimitZA = false;
                    }
                    else
                    {
                        Axis4Limit = Color.Danger;
                        if (IsAxis4 && !IsFirst)
                        {
                            IsAxis4 = false;
                            GlobalStatus.AuditLog.Add(new AuditLog() { Description = $"Z轴正限位触发", Result = Error.Error });
                            mc.GT_SetDoBit(0, mc.MC_GPO, 1, 1);
                            mc.GT_SetDoBit(0, mc.MC_GPO, 2, 0);
                            GlobalStatus.IsEmergencyStop = true;
                            GlobalStatus.IsLimitZA = true;
                        }
                    }

                    //4#负限位
                    if ((value4 & 0x40) == 0)
                    {
                        Axis4Limit2 = Color.Success;
                        IsAxis4Nav = true;
                        GlobalStatus.IsLimitZN = false;
                    }
                    else
                    {
                        Axis4Limit2 = Color.Danger;
                        if (IsAxis4Nav && !IsFirst)
                        {
                            IsAxis4Nav = false;
                            GlobalStatus.AuditLog.Add(new AuditLog() { Description = $"Z轴负限位触发", Result = Error.Error });
                            await Control.AxisOff(0, (short)MarkOptions.AxisCode.Z);
                            mc.GT_SetDoBit(0, mc.MC_GPO, 1, 1);
                            mc.GT_SetDoBit(0, mc.MC_GPO, 2, 0);
                            GlobalStatus.IsEmergencyStop = true;
                            GlobalStatus.IsLimitZN = true;
                        }
                    }

                    //2# 伺服
                    if ((value4 & 0x2) != 0)
                    {
                        if (IsServo2 && !IsFirst)
                        {
                            IsServo2 = false;
                            GlobalStatus.AuditLog.Add(new AuditLog() { Description = $"X轴伺服报警", Result = Error.Error });
                        }
                    }
                    else
                    {
                        IsServo2 = true;
                    }

                    //3# 伺服
                    if ((value4 & 0x2) != 0)
                    {
                        if (IsServo3 && !IsFirst)
                        {
                            IsServo3 = false;
                            GlobalStatus.AuditLog.Add(new AuditLog() { Description = $"Y轴伺服报警", Result = Error.Error });
                        }
                    }
                    else
                    {
                        IsServo3 = true;
                    }

                    //4# 伺服
                    if ((value4 & 0x2) != 0)
                    {
                        if (IsServo3 && !IsFirst)
                        {
                            IsServo3 = false;
                            GlobalStatus.AuditLog.Add(new AuditLog() { Description = $"Z轴伺服报警", Result = Error.Error });
                        }
                    }
                    else
                    {
                        IsServo3 = true;
                    }

                    await InvokeAsync(StateHasChanged);
                    if (IsFirst)
                    {
                        await Task.Delay(3000);
                    }
                    IsFirst = false;
                }
            }
            catch (Exception)
            {
            }
        }

        private async void Timer_Elapsed1(object? sender, ElapsedEventArgs e)
        {
            if (Master.IsConnected)
            {
                var ad = await Master.RedKeepRegister(0, 1);
                if (ad != 0)
                {
                    Height =
                        ((ad / MarkOptions.MarkArgs.MarkCoefficient + MarkOptions.MarkArgs.MarkMinHeight)).ToString(
                            "0.0000");
                }
                await InvokeAsync(StateHasChanged);
            }
        }

        private async Task OnServoX()
        {
            if (Axis2Servo == Color.Success)
            {
                await Control.AxisOn(0, (short)MarkOptions.AxisCode.X);
            }
            else
            {
                await Control.AxisOff(0, (short)MarkOptions.AxisCode.X);
            }
        }

        private async Task OnServoY()
        {
            if (Axis3Servo == Color.Success)
            {
                await Control.AxisOn(0, (short)MarkOptions.AxisCode.Y);
            }
            else
            {
                await Control.AxisOff(0, (short)MarkOptions.AxisCode.Y);
            }
        }

        private async Task OnServoZ()
        {
            if (Axis4Servo == Color.Success)
            {
                await Control.AxisOn(0, (short)MarkOptions.AxisCode.Z);
            }
            else
            {
                await Control.AxisOff(0, (short)MarkOptions.AxisCode.Z);
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }

        private void Dispose(bool dispose)
        {
            if (Token != null)
            {
                Token.Dispose();
                Token = null;
            }

            GC.SuppressFinalize(this);
        }
    }
}
